home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / cgazv4n3.zip / GETESTR.C < prev    next >
C/C++ Source or Header  |  1990-02-05  |  13KB  |  378 lines

  1. /**************** GETESTR.C *************
  2.     Get an editable string
  3.     (c) Copyright 1989, The C Gazette
  4.     Use freely as long as authorship is acknowledged
  5.  
  6.     Andrew Binstock  v. 1.4
  7.     Validated for MSC, Turbo C
  8.  ***************************************/
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <dos.h>
  13. #include <conio.h>
  14. #include <ctype.h>
  15. #include <string.h>
  16.  
  17. #define DRIVER  1                 /* Enables running main() as a demo */
  18.  
  19. #define HOME    0x4700            /* Special Case - Editing Keys      */
  20. #define S_HOME  0x4737
  21. #define C_HOME  0x7700
  22. #define END     0x4F00
  23. #define S_END   0x4F31
  24. #define C_END   0x7500
  25. #define ESC     0x011B
  26. #define ENTER   0x1C0D
  27. #define LEFT    0x4B00
  28. #define RIGHT   0x4D00
  29. #define BACKSP  0x0E08
  30. #define INSERT  0x5200
  31. #define DELETE  0x5300
  32. #define TAB_KEY 0x0F09
  33. #define BK_TAB  0x0F00
  34.  
  35. #define TABSIZE 8
  36. #define TAB     0x09
  37.  
  38. #define Insert    1
  39. #define Overwrite 0
  40.  
  41. #define ON        1               /* For hiding/showing the cursor */
  42. #define OFF       0
  43. #define LINE      2               /* For cursor shape on Ins/Ovrwr */
  44. #define BLOCK     3
  45.  
  46. #define update_cursor() set_cursor(pos, srow, scol)
  47. #define update_line()   set_cursor(pos, srow, scol); cputs((char *)(buff+pos))
  48.  
  49. static int Shape;
  50.  
  51. static void set_cursor(int, int, int);
  52. static void cursor(int);
  53. int get_basic_video_type(void);
  54.  
  55. char * getestr(char * const curr,               /* current string, if any   */
  56.                         int srow, int scol,     /* starting location        */
  57.                         size_t slen,            /* maximum string length    */
  58.                         char insert_mode        /* start in Ins or Ovrwrite */
  59.                    )
  60. {
  61.     union REGS inregs, outregs;
  62.     int i, j, c, done, pos;
  63.     char *buff;
  64.  
  65.     done = 0;
  66.     buff = (char *) calloc(1, slen + 1);    /* Our buffer */
  67.  
  68.     /* position cursor at row, col */
  69.     set_cursor(0, srow, scol);
  70.  
  71.     i = j = 0;
  72.  
  73.     /* copy slen chars of curr to screen */
  74.     if (*curr != NULL)
  75.         for (;j < slen && curr[i];  i++,  j++)   /* i = char in  */
  76.         {                                        /* j = char out */
  77.             if (curr[i] == TAB)
  78.             {       /* expand tabs to TABSIZE */
  79.  
  80.                 int cols_to_go = TABSIZE - (j % TABSIZE);
  81.  
  82.                 do
  83.                 {
  84.                     putch(' ');
  85.                     buff[j] = ' ';
  86.                     j++;
  87.                 }
  88.                 while (j < slen && --cols_to_go > 0);
  89.  
  90.                 j--;    /* We're at the next column, so back up 1 */
  91.             }
  92.             else
  93.             {           /* If it's not a tab just write it out */
  94.                 putch(curr[i]);
  95.                 buff[j] = curr[i];
  96.             }
  97.         }
  98.  
  99.     while (j < slen)    /* Pad the string with spaces */
  100.         buff[j++] = ' ';
  101.     buff[slen] = '\0';
  102.  
  103.     pos = 0;            /* Move cursor to start of string */
  104.     update_cursor();
  105.  
  106.     while (!done)       /* Process keystrokes until done  */
  107.     {
  108.         inregs.h.ah = 0x0;           /* get key */
  109.         int86(0x16, &inregs, &outregs);
  110.         switch (outregs.x.ax)        /* contains scan-code - ASCII code */
  111.         {
  112.             case HOME:
  113.             case S_HOME:
  114.             case C_HOME:
  115.                 pos = 0;
  116.                 update_cursor();
  117.                 break;
  118.             case END:
  119.             case S_END:
  120.             case C_END:
  121.                 for (pos = slen - 1;  pos >= 0;  pos--)
  122.                     if (pos == 0 || isgraph(buff[pos]))
  123.                         break;
  124.                 if (pos != slen - 1)
  125.                     pos += 1;   /* one char beyond EOS */
  126.                 update_cursor();
  127.                 break;
  128.             case ESC:
  129.             case ENTER:
  130.                 done = 1;
  131.                 break;
  132.             case LEFT:
  133.                 if (pos > 0)
  134.                     pos--;
  135.                 update_cursor();
  136.                 break;
  137.             case RIGHT:
  138.                 if (pos < slen - 1)
  139.                     pos++;
  140.                 update_cursor();
  141.                 break;
  142.             case BACKSP:
  143.                 if (pos == 0)
  144.                     break;
  145.                 if (insert_mode == Overwrite)
  146.                     /* In overwrite mode,      */
  147.                 {       /* just blank char at left */
  148.                     buff[--pos] = ' ';
  149.                     cursor(OFF);
  150.                     update_line();
  151.                     update_cursor();
  152.                     cursor(ON);
  153.                 }
  154.                 else
  155.                 {
  156.                     cursor(OFF);
  157.                     for (i = slen - 1;  i >= 0;  i--)
  158.                         if (i == 0 || isgraph(buff[i]))
  159.                             break;
  160.                     pos--;
  161.                     strcpy((void *) (buff + pos), (void *) (buff + pos + 1));
  162.                     buff[slen - 1] = ' ';
  163.                     update_line();
  164.                     update_cursor();
  165.                     cursor(ON);
  166.                 }
  167.                 break;
  168.             case TAB_KEY:
  169.             {
  170.                 int cols_to_go = (TABSIZE - pos % TABSIZE);
  171.                 if (insert_mode == Overwrite)  /* just move the cursor */
  172.                 {
  173.                     if ((pos += cols_to_go) > slen - 1)
  174.                         pos = slen - 1;
  175.                     update_cursor();
  176.                 }
  177.                 else                           /* otherwise insert spaces */
  178.                 {
  179.                     int k;
  180.                     for (i = slen - 1; i >= 0; i--)       /* how many spaces  */
  181.                         if (i == 0 || isgraph(buff[i]))   /* at end of buff?  */
  182.                             break;
  183.  
  184.                     j = min (cols_to_go, (slen - 1) - i);  /* insert the      */
  185.                     memmove ((void *) (buff + pos + j - 1),/* lesser of cols_ */
  186.                              (void *) (buff + pos - 1),    /* to_go and # of  */
  187.                               slen - pos);                 /* spaces left.    */
  188.                     buff[slen] = '\0';
  189.                     cursor (OFF);
  190.                     for (k=j; j >= 0; j--)
  191.                         buff [pos+j - 1] = ' ';
  192.                     update_line();
  193.                     pos += k;
  194.                     update_cursor();
  195.                     cursor(ON);
  196.                 }
  197.             }
  198.                 break;
  199.             case BK_TAB:    /* back tab -- only moves the cursor */
  200.             {
  201.                 int cols_to_go = pos % TABSIZE;
  202.                 if (cols_to_go == 0)
  203.                     cols_to_go = TABSIZE;
  204.                 if ((pos -= cols_to_go) < 0)
  205.                     pos = 0;
  206.                 update_cursor();
  207.             }
  208.                 break;
  209.             case DELETE:
  210.             {
  211.                 cursor(OFF);
  212.                 for (i = slen - 1;  i >= 0;  i--)   /* Find last non-space */
  213.                     if (i == 0 || isgraph(buff[i])) /* in the string.      */
  214.                         break;
  215.                 strcpy((void *) (buff + pos), (void *) (buff + pos + 1));
  216.                 buff[slen - 1] = ' ';
  217.  
  218.                 update_line();
  219.                 update_cursor();
  220.                 cursor(ON);
  221.             }
  222.                 break;
  223.             case INSERT:
  224.                 if (insert_mode == Overwrite)
  225.                 {
  226.                     insert_mode = Insert;
  227.                     Shape = BLOCK;
  228.                 }
  229.                 else
  230.                 {
  231.                     insert_mode = Overwrite;
  232.                     Shape = LINE;
  233.                 }
  234.                 cursor(ON);
  235.                 break;
  236.             default:        /* print any printable character */
  237.             {
  238.                 if (!(pos < slen))  /* If beyond EOL, beep */
  239.                 {
  240.                     putchar('\a');
  241.                     break;
  242.                 }
  243.  
  244.                 if (isprint(c=outregs.h.al))
  245.                 {
  246.                     if (insert_mode == Overwrite)
  247.                     {
  248.                         buff[pos] = (char) c;
  249.                         cursor(OFF);
  250.                         update_line();
  251.                         pos++;
  252.                         update_cursor();
  253.                         cursor(ON);
  254.                     }
  255.                     else    /* mode is Insert */
  256.                     {
  257.                         if (! isspace(buff[slen-1]))
  258.                         {
  259.                             putchar('\a');
  260.                             break;
  261.                         }
  262.                         else
  263.                         {   /* memcpy won't work --- overlapping move */
  264.                             memmove((void *) (buff + pos + 1),
  265.                                     (void *) (buff + pos),
  266.                                      slen - pos - 1);
  267.                             buff[slen] = '\0';
  268.                             buff[pos] = (char) c;
  269.                             cursor(OFF);
  270.                             update_line();
  271.                             pos++;
  272.                             update_cursor();
  273.                             cursor(ON);
  274.                         }
  275.                     }
  276.                     break;
  277.                 }
  278.             }       /* end of default */
  279.         }           /* end of switch */
  280.     }               /* end of while */
  281.  
  282.     strcpy(curr, buff);
  283.     return (curr);
  284. }
  285.  
  286. static void set_cursor(int col, int offset_row, int offset_col)
  287. {                              /* set cursor position: int 10h, service 2 */
  288.     union REGS inregs, outregs;
  289.     static int page = -1;
  290.  
  291.     if (page == -1)     /* Since page cannot be -1 */
  292.     {                   /* this will be done once  */
  293.         inregs.h.ah = 0xF;
  294.         int86(0x10, &inregs, &outregs);
  295.         page = outregs.h.bh;
  296.     }
  297.  
  298.     inregs.h.ah = 0x02;
  299.     inregs.h.dh = (char) offset_row;
  300.     inregs.h.dl = (char) col + offset_col;
  301.     inregs.h.bh = (char) page;
  302.     int86(0x10, &inregs, &outregs);
  303. }
  304.  
  305. static void cursor(int status)  /* Cursor on/off function */
  306. {
  307.     union REGS inregs, outregs;
  308.     static unsigned int top, bottom;    /* cursor scan lines */
  309.  
  310.     if ((top | bottom) == 0)    /* if neither of them has been identified */
  311.     {                           /* only executed the first time through   */
  312.         switch (get_basic_video_type())
  313.         {
  314.                                             /* top and bottom are the    */
  315.             case 1:         /* MDA  */      /* scan lines for the cursor */
  316.                                             /* when it appears as an un- */
  317.             default:                        /* derscore. If the cursor is*/
  318.                 top = 12;                   /* a block the value of top  */
  319.                 bottom = 13;                /* is zero. This is due to   */
  320.                 break;                      /* the way scan lines are    */
  321.             case 2:         /* CGA  */      /* numbered: 0 to n, where 0 */
  322.             case 3:         /* EGA  */      /* is the topmost line.      */
  323.                 top = 6;
  324.                 bottom = 7;
  325.                 break;
  326.             case 4:         /* VGA */
  327.                 top = 13;
  328.                 bottom = 14;
  329.                 break;
  330.         }
  331.     }
  332.  
  333.  
  334.     inregs.h.ah = 0x1;  /* Service to set cursor size */
  335.     inregs.h.cl = (char) bottom;
  336.     inregs.h.ch = (char) (Shape == BLOCK ? 0 : top);
  337.     if (status == OFF)
  338.         inregs.h.ch |= 0x10;    /* When bit 4 is on cursor is hidden */
  339.     int86(0x10, &inregs, &outregs);
  340. }
  341.  
  342. int get_basic_video_type(void)   /* Very broad test for basic video type.    */
  343. {                                /* For more details on the technique, see   */
  344.     union REGS inregs, outregs;  /* my article, "Identifying Video Systems", */
  345.                                  /* in The C Gazette, Vol 4, No. 1           */
  346.     inregs.h.ah = 0x1A;
  347.     inregs.h.al = 0x0;
  348.     int86(0x10, &inregs, &outregs);
  349.     if (outregs.h.al == 0x1A)   /* True for VGA and MCGA */
  350.         return 4;
  351.  
  352.     inregs.h.ah = 0x12;
  353.     inregs.h.bl = 0x10;
  354.     int86(0x10, &inregs, &outregs);
  355.     if (outregs.h.bl != 0x10)   /* True for EGA */
  356.         return 3;
  357.  
  358.     inregs.h.ah = 0xF;
  359.     int86(0x10, &inregs, &outregs);
  360.     if (outregs.h.al == 0x7)    /* True for mono */
  361.         return 1;
  362.     else
  363.         return 2;               /* else it's a CGA */
  364. }
  365.  
  366. #ifdef DRIVER   /* Test driver for routine */
  367. int main (void)
  368. {
  369.     char *pp;
  370.     static char * p = "this is the forest prime";
  371.     pp = getestr(p, 10, 10, 28, Overwrite);
  372.     putchar('\n');
  373.     puts(pp);
  374.     return (0);
  375. }
  376.  
  377. #endif
  378.